#ifndef SFML_GLPRIMATIVE_HPP
#define SFML_GLPRIMATIVE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/System/Vector2.hpp>
#include <vector>

namespace sf
{
class RenderWindow;
class Image;

////////////////////////////////////////////////////////////
/// Enumerate the render modes for GLPrimatives
////////////////////////////////////////////////////////////
namespace Render
{
    enum Mode
    {
        Points,
        Lines,
        Line_Strip,
        Line_Loop,
        Triangles,
        Triangle_Strip,
        Triangle_Fan,
        Quads,
        Quad_Strip,
        Polygon
    };
}

////////////////////////////////////////////////////////////
/// GLPrimative defines a OpenGL graphical primative
////////////////////////////////////////////////////////////
class SFML_API GLPrimative : public sf::Drawable
{
public:

    ////////////////////////////////////////////////////////////
    /// Default constructor
    ///
    ////////////////////////////////////////////////////////////
    GLPrimative( Render::Mode Mode = Render::Points );

    ////////////////////////////////////////////////////////////
    /// Set the render mode for the primative.
    /// The default render mode is Render::Points
    ///
    /// \param Mode : New Render mode
    ///
    ////////////////////////////////////////////////////////////
    void SetRenderMode( Render::Mode Mode );

    ////////////////////////////////////////////////////////////
    /// Get the currnet render mode for the primative.
    ///
    /// \return Current render mode
    ///
    ////////////////////////////////////////////////////////////
    Render::Mode GetRenderMode() const;

    ////////////////////////////////////////////////////////////
    /// Set the image used to render the primative
    ///
    /// \param Image : New Image
    ///
    ////////////////////////////////////////////////////////////
    void SetImage( const Image& Image );

    ////////////////////////////////////////////////////////////
    /// Get the image used to render the primative
    ///
    /// \return Current image
    ///
    ////////////////////////////////////////////////////////////
    const Image* GetImage() const;
   
    ////////////////////////////////////////////////////////////
    /// Add a vertex to the primative
    ///
    /// \param X, Y : Position of the next vertex
    ///
    ////////////////////////////////////////////////////////////
    void AddVertex( float X, float Y );

    ////////////////////////////////////////////////////////////
    /// Add a vertex to the primative
    ///
    /// \param Position : Position of the next vertex
    ///
    ////////////////////////////////////////////////////////////
    void AddVertex( const Vector2f& Position );

    ////////////////////////////////////////////////////////////
    /// Add a vertex to the primative
    ///
    /// \param X, Y : Position of the next vertex
    /// \param Col  : Color of the next vertex
    ///
    ////////////////////////////////////////////////////////////
    void AddVertex( float X, float Y, const Color& Col );

    ////////////////////////////////////////////////////////////
    /// Add a vertex to the primative
    ///
    /// \param Position : Position of the next vertex
    /// \param Col      : Color of the next vertex
    ///
    ////////////////////////////////////////////////////////////
    void AddVertex( const Vector2f& Position, const Color& Col );

    ////////////////////////////////////////////////////////////
    /// Add a vertex to the primative
    ///
    /// \param X, Y : Position of the next vertex
    /// \param U, V : Image pixel of the next vertex
    ///
    ////////////////////////////////////////////////////////////
    void AddVertex( float X, float Y, unsigned U, unsigned V );

    ////////////////////////////////////////////////////////////
    /// Add a vertex to the primative
    ///
    /// \param Position : Position of the next vertex
    /// \param Pixel    : Image pixel of the next vertex
    ///
    ////////////////////////////////////////////////////////////
    void AddVertex( const Vector2f& Position, const Vector2i& Pixel );

protected:

    ////////////////////////////////////////////////////////////
    /// /see Drawable::Render
    ///
    ////////////////////////////////////////////////////////////
    virtual void Render( RenderTarget& Window ) const;

private:

    ////////////////////////////////////////////////////////////
    /// Compile the primative : compute its UV coords
    ///
    ////////////////////////////////////////////////////////////
    void Compile() const;

    ////////////////////////////////////////////////////////////
    /// Defines a storage for GL command
    ////////////////////////////////////////////////////////////
    struct Vertex
    {
      ////////////////////////////////////////////////////////////
      /// Construct a color vertex
      ////////////////////////////////////////////////////////////
       Vertex( const Vector2f& XY, const Color& C );

       ////////////////////////////////////////////////////////////
       /// Construct a color vertex
       ////////////////////////////////////////////////////////////
       Vertex( const Vector2f& XY, const Vector2i& P );

       ////////////////////////////////////////////////////////////
       /// execute the glColor* command for this vertex
       ////////////////////////////////////////////////////////////
       void glColor() const;

       ////////////////////////////////////////////////////////////
       /// execute the glTexCoord* command for this vertex
       ////////////////////////////////////////////////////////////
       void glTexCoord() const;

       ////////////////////////////////////////////////////////////
       /// execute the glVertex* command for this vertex
       ////////////////////////////////////////////////////////////
       void glVertex() const;

       Vector2f Vert;       ///< Vertex position
       Vector2i Pixel;      ///< Pixel in of image at this vertex
       Color    Col;        ///< Vertex color
       mutable Vector2f UV;         ///< UV of image at this vertex
       mutable float    R, G, B, A; ///< Compiled color
    };

    ////////////////////////////////////////////////////////////
    // member data
    ////////////////////////////////////////////////////////////
    const Image*        myImage;      ///< Image used during Render
    std::vector<Vertex> myVertices;   ///< Verticies composing the primative
    Render::Mode        myRenderMode; ///< OpenGL render mode
    mutable bool                myIsCompiled; ///< Compiled state of primative
};


} // namespace sf

#endif // SFML_GLPRIMATIVE_HPP
